//
// Created by tan on 22-8-20.
//

#ifndef PCB_TOOLS_H
#define PCB_TOOLS_H

#include <set>
#include <iomanip>
#include <cstring>
#include <regex>
#include "rapidcsv.h"


using namespace rapidcsv;
using namespace std;

class Tools {
public:

    static vector<string> split(string str, const string &pat) {
        string::size_type pos;
        vector<string> result;

        str += pat;//扩展字符串以方便操作
        int size = (int) str.size();

        for (int i = 0; i < size; i++) {
            pos = str.find(pat, i);
            if (pos < size) {
                string s = str.substr(i, pos - i);
                result.push_back(s);
                i = pos + pat.size() - 1;
            }
        }
        return result;
    }


    static string &ltrim(string &str, const string &pat) {
        int position;
        position = (int) str.find_first_not_of(pat);
        while (position > 0) {
            str.erase(0, position);
            position = (int) str.find_first_not_of(pat);
        }
        return str;
    }

    static string &rtrim(string &str, const string &chars) {
        int position;
        position = (int) str.find_last_not_of(chars);
        while (position + 1 != str.length()) {
            str.erase(str.find_last_not_of(chars) + 1);
            position = (int) str.find_last_not_of(chars);
        }
        return str;
    }

    static string &trim(string &str, const string &chars) {
        return rtrim(ltrim(str, chars), chars);
    }

    static char *str2char(string &str) {
        char *arr = new char[str.size() + 1];
        strcpy(arr, str.c_str());
        return arr;
    }


    static double **str2arr(const string &cell) {
        vector<string> res = split(cell, ",");
        int size = (int) res.size();
        auto **points = new double *[size];
        string tmp;
        string sp;

        for (int i = 0; i < size; i = i + 2) {
            auto *curPoint = new double[2];
            string chr1 = res[i];
            sp = " ";
            tmp = trim(chr1, sp);
            sp = "[";
            tmp = trim(tmp, sp);
            sp = "]";
            tmp = trim(tmp, sp);
            double x = atof(tmp.c_str());

            string chr2 = res[i + 1];
            sp = " ";
            tmp = trim(chr2, sp);
            sp = "[";
            tmp = trim(tmp, sp);
            sp = "]";
            tmp = trim(tmp, sp);
            double y = atof(tmp.c_str());
//            cout << "x: " << x << endl;
            curPoint[0] = x;
            curPoint[1] = y;
            points[i] = curPoint;
        }

        return points;
    }


    static vector<string> read_file(const string &filepath) {
        /**
         * read "csv、txt..." file
         **/
        vector<string> lines;
        ifstream ifs(filepath);

        if (!ifs.is_open()) {
            cout << "open file error " << filepath << endl;
        }

        string ss;
        while (getline(ifs, ss)) {
            lines.emplace_back(ss);
        };

        return lines;
    }

    static vector<string> read_str(const string &columnName, const Document &doc) {
        /**
         * read csv column as string
         * **/
        cout << "string columnName: " << columnName << endl;
        doc.GetColumn<string>(columnName);
        return doc.GetColumn<string>(columnName);
    }

    static vector<double> read_double(const string &columnName, const Document &doc) {
        /**
         * read csv column as double
         * **/
        vector<double> res;
        vector<string> lines = doc.GetColumn<string>(columnName);
        for (string &line: lines) {
            res.push_back(atof(line.c_str()));
        }
        return res;
    }

    static vector<double> cell2arr(const string &cell) {
        /**
         * read csv cell to array
         * **/
        vector<string> res = split(cell, ",");
        int size = (int) res.size();

        string tmp;
        string sp;
        vector<double> linePoints;
        for (int i = 0; i < size; ++i) {
            string chr = res[i];
            sp = " ";
            tmp = trim(chr, sp);
            sp = "[";
            tmp = trim(tmp, sp);
            sp = "]";
            tmp = trim(tmp, sp);
            double x = atof(tmp.c_str());
            linePoints.push_back(x);
        }
        return linePoints;
    }

    static vector<vector<double>> read_arr(const string &columnName, const Document &document) {
        vector<string> lines = document.GetColumn<string>(columnName);
        int len = (int) lines.size();
        vector<vector<double>> arrays;

        for (int i = 0; i < len; ++i) {
            string line = lines[i];
            vector<double> tmp = cell2arr(line);
            arrays.push_back(tmp);
        }

        return arrays;
    }
};

static int getNo(string &inStr, const regex &re = regex(".*[a-z]+(\\d+)$")) {
    /**
     * Get the string last Number
     * **/
    smatch result;
    if (regex_match(inStr, result, re)) {
        string str = result[1];
        return atof(str.c_str());
    } else {
        cerr << "Get point Number error, convert failed in " << __FILE__ << " Line " << __LINE__ << endl;
        return -1;
    }
}

template<typename T>
static void printSet(const set<T> &numbers) {
    for (const auto &item: numbers) {
        cout << item << " ";
    }
    cout << endl;
}

template<typename T>
static void printVector(const vector<T> &vec) {
    for (const auto &item: vec) {
        cout << item << " ";
    }
    cout << endl;
}

static double precision(double inNum, int pre = 5) {
    stringstream ss;
    ss.setf(ios::fixed);
    ss.precision(pre);
    ss << inNum;
    return atof(ss.str().c_str());
}

#endif //PCB_TOOLS_H
